#!/usr/bin/env python3
"""
小米汽车事故与安全分析脚本
分析小米汽车相关新闻，重点关注事故、安全和质量问题，进行语义分析和可视化
"""

import os
import sys
import json
import time
import requests
from datetime import datetime, timedelta
from collections import Counter, defaultdict
import re
import jieba
import jieba.posseg as pseg
from wordcloud import WordCloud
import matplotlib.pyplot as plt
import plotly.graph_objects as go
import plotly.express as px
import networkx as nx
import pandas as pd
import numpy as np
from bs4 import BeautifulSoup
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.decomposition import LatentDirichletAllocation
import warnings
warnings.filterwarnings('ignore')

# 添加项目路径
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

# 尝试导入项目辅助函数，如果失败则使用备用方案
try:
    from src.bootstrap_helpers import (
        setup_logging, log_info, log_warning, log_error,
        set_chinese_font, create_progress_bar
    )
except ImportError:
    # 备用日志函数
    def setup_logging():
        pass
    
    def log_info(msg):
        print(f"[INFO] {msg}")
    
    def log_warning(msg):
        print(f"[WARNING] {msg}")
    
    def log_error(msg):
        print(f"[ERROR] {msg}")
    
    def set_chinese_font():
        import matplotlib.pyplot as plt
        plt.rcParams['font.sans-serif'] = ['SimHei', 'Arial Unicode MS', 'DejaVu Sans']
        plt.rcParams['axes.unicode_minus'] = False
    
    def create_progress_bar():
        return None

def setup_environment():
    """设置中文字体和日志"""
    setup_logging()
    set_chinese_font()
    log_info("开始小米汽车事故与安全分析")

def search_xiaomi_car_news():
    """
    搜索小米汽车相关新闻数据，重点关注事故、安全和质量问题
    这里使用模拟数据作为演示，实际应用中应该从新闻API或网页爬取
    """
    log_info("搜索小米汽车相关新闻数据...")
    
    # 模拟小米汽车相关新闻数据，包含各种类型（正面、负面、中性）
    news_data = [
        {
            "title": "小米SU7首月交付破万，创国产电动车新纪录",
            "content": "小米汽车SU7上市首月交付量突破1万辆，创下国产电动车交付新纪录，市场反响热烈。",
            "date": "2024-03-15",
            "source": "汽车之家",
            "sentiment": "positive",
            "category": "delivery"
        },
        {
            "title": "小米SU7高速行驶中突发刹车失灵，车主险酿事故",
            "content": "一位小米SU7车主在高速行驶时遭遇刹车失灵故障，车辆险些追尾前车，引发安全担忧。",
            "date": "2024-04-05",
            "source": "汽车安全网",
            "sentiment": "negative",
            "category": "accident"
        },
        {
            "title": "小米汽车电池系统通过国家安全认证，续航表现优异",
            "content": "小米SU7电池系统通过国家新能源汽车安全认证，续航里程达到官方标称水平。",
            "date": "2024-04-20",
            "source": "新能源汽车报",
            "sentiment": "positive",
            "category": "safety"
        },
        {
            "title": "小米SU7发生首起严重交通事故，车辆损毁严重",
            "content": "一辆小米SU7在高速公路上发生严重碰撞事故，车辆前部严重损毁，安全气囊正常弹出。",
            "date": "2024-05-10",
            "source": "交通事故通报",
            "sentiment": "negative",
            "category": "accident"
        },
        {
            "title": "小米汽车启动首次召回，涉及制动系统软件升级",
            "content": "小米汽车宣布召回部分SU7车型，对制动系统控制软件进行升级优化，提升安全性。",
            "date": "2024-05-25",
            "source": "国家质检总局",
            "sentiment": "neutral",
            "category": "recall"
        },
        {
            "title": "小米SU7自动驾驶系统表现稳定，获得用户好评",
            "content": "多位小米SU7车主反馈自动驾驶系统在城市道路和高速公路上表现稳定可靠。",
            "date": "2024-06-12",
            "source": "智能汽车评测",
            "sentiment": "positive",
            "category": "autopilot"
        },
        {
            "title": "小米汽车充电过程中发生自燃事故，原因正在调查",
            "content": "一辆正在充电的小米SU7发生自燃事故，消防部门及时处置，事故原因正在调查中。",
            "date": "2024-07-08",
            "source": "新能源汽车安全",
            "sentiment": "negative",
            "category": "accident"
        },
        {
            "title": "小米汽车获得欧洲安全认证，计划进军海外市场",
            "content": "小米SU7通过欧洲NCAP安全测试，获得五星安全评级，为海外市场拓展奠定基础。",
            "date": "2024-08-15",
            "source": "国际汽车新闻",
            "sentiment": "positive",
            "category": "safety"
        },
        {
            "title": "小米SU7雨天失控撞护栏，车主质疑车辆稳定性",
            "content": "一位车主反映小米SU7在雨天行驶时出现失控现象，车辆撞向护栏，车主质疑车辆稳定性。",
            "date": "2024-09-20",
            "source": "车主投诉平台",
            "sentiment": "negative",
            "category": "accident"
        },
        {
            "title": "小米汽车发布安全驾驶报告，事故率低于行业平均",
            "content": "小米汽车发布首份安全驾驶报告，显示SU7事故率低于同级别电动车平均水平。",
            "date": "2024-10-05",
            "source": "小米官方",
            "sentiment": "positive",
            "category": "safety"
        },
        {
            "title": "小米SU7与货车相撞事故，安全气囊保护驾驶员",
            "content": "一辆小米SU7与货车发生碰撞事故，车辆安全气囊及时弹出，驾驶员仅受轻伤。",
            "date": "2024-10-18",
            "source": "交通事故快报",
            "sentiment": "neutral",
            "category": "accident"
        },
        {
            "title": "小米汽车开展冬季安全测试，应对极端天气挑战",
            "content": "小米汽车在东北地区开展冬季安全测试，验证车辆在极端低温环境下的性能表现。",
            "date": "2024-11-12",
            "source": "汽车测试周刊",
            "sentiment": "neutral",
            "category": "testing"
        }
    ]
    
    log_info(f"收集到 {len(news_data)} 条小米汽车相关新闻")
    return news_data

def preprocess_text(text):
    """文本预处理：分词、去停用词"""
    # 加载停用词
    stopwords = set(['的', '了', '在', '是', '我', '有', '和', '就',
                    '不', '人', '都', '一', '一个', '上', '也', '很',
                    '到', '说', '要', '去', '你', '会', '着', '没有',
                    '看', '好', '自己', '这', '那', '他', '她', '它',
                    '小米'])  # 移除小米品牌词
    
    # 中文分词
    words = jieba.cut(text)
    # 过滤停用词和标点符号
    filtered_words = [word for word in words if word.strip() and word not in stopwords and len(word) > 1]
    
    return filtered_words

def extract_keywords(news_data, top_n=50):
    """提取关键词和词频统计"""
    log_info("提取关键词...")
    
    all_words = []
    for news in news_data:
        words = preprocess_text(news['title'] + ' ' + news['content'])
        all_words.extend(words)
    
    # 词频统计
    word_freq = Counter(all_words)
    top_keywords = word_freq.most_common(top_n)
    
    return top_keywords, word_freq

def perform_lda_analysis(news_data, num_topics=5):
    """LDA主题建模分析"""
    log_info("进行LDA主题建模分析...")
    
    # 准备文档语料
    documents = [news['title'] + ' ' + news['content'] for news in news_data]
    
    # TF-IDF向量化
    vectorizer = TfidfVectorizer(max_features=1000, stop_words=None)
    X = vectorizer.fit_transform(documents)
    
    # LDA模型
    lda = LatentDirichletAllocation(n_components=num_topics, random_state=42)
    lda.fit(X)
    
    # 获取主题关键词
    feature_names = vectorizer.get_feature_names_out()
    topics = []
    for topic_idx, topic in enumerate(lda.components_):
        top_words_idx = topic.argsort()[:-11:-1]
        top_words = [feature_names[i] for i in top_words_idx]
        topics.append({
            'topic_id': topic_idx,
            'top_words': top_words,
            'weight': topic.sum()
        })
    
    return topics

def create_wordcloud(word_freq):
    """生成词云图 - 采用爆炸形状美化"""
    log_info("生成词云图...")
    
    # 确保输出目录存在
    os.makedirs('figures', exist_ok=True)
    
    # 尝试不同的中文字体路径
    font_paths = [
        '/System/Library/Fonts/PingFang.ttc',  # macOS
        '/System/Library/Fonts/Arial Unicode.ttf',  # macOS
        '/Library/Fonts/Arial Unicode.ttf',  # macOS
        '/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf',  # Linux
        'C:/Windows/Fonts/simhei.ttf'  # Windows
    ]
    
    font_path = None
    for fp in font_paths:
        if os.path.exists(fp):
            font_path = fp
            break
    
    if font_path is None:
        font_path = None  # 使用默认字体
        log_info("未找到中文字体，使用默认字体")
    
    # 创建爆炸形状的掩码
    x, y = np.ogrid[:600, :800]
    mask = (x - 300) ** 2 + (y - 400) ** 2 > 250 ** 2
    mask = 255 * mask.astype(int)
    
    # 创建词云图 - 使用爆炸形状和美化配色
    wordcloud = WordCloud(
        font_path=font_path,
        width=800,
        height=600,
        background_color='#1a1a2e',  # 深蓝色背景
        colormap='plasma',  # 等离子配色
        mask=mask,
        max_words=80,
        contour_width=2,
        contour_color='steelblue',
        relative_scaling=0.5,
        random_state=42
    ).generate_from_frequencies(word_freq)
    
    # 保存词云图
    plt.figure(figsize=(14, 10))
    plt.imshow(wordcloud, interpolation='bilinear')
    plt.axis('off')
    plt.title('图1: 小米汽车新闻关键词词云（爆炸形状）', 
              fontsize=18, pad=20, color='white', 
              bbox=dict(boxstyle="round,pad=0.3", facecolor='#16213e', alpha=0.8))
    plt.tight_layout()
    plt.savefig('figures/xiaomi_car_wordcloud.png', dpi=300, bbox_inches='tight', 
                facecolor='#1a1a2e', edgecolor='none')
    plt.close()
    
    log_info(f"词云图已保存至: figures/xiaomi_car_wordcloud.png")

def create_network_diagram(news_data, output_path='figures/xiaomi_car_network.png'):
    """创建静态网络图PNG格式"""
    log_info("创建网络图...")
    
    # 确保输出目录存在
    os.makedirs('figures', exist_ok=True)
    
    # 提取关键实体和关系
    entities = {}
    
    for news in news_data:
        # 提取产品相关实体
        text = news['title'] + ' ' + news['content']
        words = pseg.cut(text)
        
        for word, flag in words:
            if flag in ['n', 'ns', 'nt', 'nz'] and len(word) > 1 and word != '小米':
                if word not in entities:
                    entities[word] = {'count': 0, 'dates': []}
                entities[word]['count'] += 1
                entities[word]['dates'].append(news['date'])
    
    # 过滤低频实体
    filtered_entities = {k: v for k, v in entities.items() if v['count'] >= 2}
    
    # 创建网络图
    G = nx.Graph()
    
    # 添加节点
    for entity, info in filtered_entities.items():
        G.add_node(entity, size=info['count'], dates=info['dates'])
    
    # 添加边（基于共现关系）
    for news in news_data:
        text = news['title'] + ' ' + news['content']
        entities_in_news = [e for e in filtered_entities.keys() if e in text]
        
        for i, entity1 in enumerate(entities_in_news):
            for entity2 in entities_in_news[i+1:]:
                if G.has_edge(entity1, entity2):
                    G[entity1][entity2]['weight'] += 1
                else:
                    G.add_edge(entity1, entity2, weight=1)
    
    # 创建静态网络图
    plt.figure(figsize=(16, 12))
    
    # 计算节点大小
    node_sizes = [G.nodes[node]['size'] * 500 for node in G.nodes()]
    
    # 使用spring布局
    pos = nx.spring_layout(G, k=1, iterations=50)
    
    # 绘制网络图
    nx.draw_networkx_nodes(G, pos, 
                          node_size=node_sizes,
                          node_color='lightblue',
                          alpha=0.7,
                          edgecolors='darkblue',
                          linewidths=2)
    
    nx.draw_networkx_edges(G, pos, 
                          width=1.5,
                          alpha=0.5,
                          edge_color='gray')
    
    # 添加节点标签 - 使用更可靠的中文字体设置
    labels = {node: node for node in G.nodes()}
    
    # 尝试不同的中文字体
    font_properties = {'font_size': 10}
    
    # 尝试设置中文字体，如果失败则使用默认字体
    try:
        plt.rcParams['font.sans-serif'] = ['SimHei', 'Microsoft YaHei', 'Arial Unicode MS', 'DejaVu Sans']
        plt.rcParams['axes.unicode_minus'] = False
        font_properties['font_family'] = 'SimHei'
    except:
        log_warning("中文字体设置失败，使用默认字体")
    
    nx.draw_networkx_labels(G, pos, labels, **font_properties)
    
    plt.title('图2: 小米汽车新闻实体关系网络图', fontsize=16, pad=20)
    plt.axis('off')
    plt.tight_layout()
    plt.savefig(output_path, dpi=300, bbox_inches='tight', 
                facecolor='white', edgecolor='none')
    plt.close()
    
    log_info(f"网络图已保存至: {output_path}")

def create_sentiment_pie_chart(news_data):
    """创建情感分布饼图"""
    log_info("创建情感分布饼图...")
    
    # 统计情感分布
    sentiment_counts = defaultdict(int)
    for news in news_data:
        sentiment_counts[news['sentiment']] += 1
    
    # 创建饼图
    labels = ['积极', '中性', '负面']
    sizes = [sentiment_counts.get('positive', 0), 
             sentiment_counts.get('neutral', 0), 
             sentiment_counts.get('negative', 0)]
    colors = ['#4CAF50', '#FFC107', '#F44336']
    
    plt.figure(figsize=(10, 8))
    plt.pie(sizes, labels=labels, colors=colors, autopct='%1.1f%%', 
            startangle=90, shadow=True, explode=(0.05, 0.05, 0.05))
    plt.axis('equal')
    plt.title('图3: 小米汽车新闻情感分布', fontsize=16, pad=20)
    plt.tight_layout()
    plt.savefig('figures/xiaomi_car_sentiment_pie.png', dpi=300, bbox_inches='tight')
    plt.close()
    
    log_info("情感分布饼图已保存至: figures/xiaomi_car_sentiment_pie.png")

def create_accident_type_chart(news_data):
    """创建事故类型分布图"""
    log_info("创建事故类型分布图...")
    
    # 统计事故类型
    category_counts = defaultdict(int)
    for news in news_data:
        if news['category'] == 'accident':
            # 从标题中提取事故类型
            title = news['title']
            if '刹车失灵' in title or '制动' in title:
                category_counts['刹车失灵'] += 1
            elif '碰撞' in title or '相撞' in title:
                category_counts['碰撞事故'] += 1
            elif '自燃' in title:
                category_counts['自燃事故'] += 1
            elif '失控' in title:
                category_counts['失控事故'] += 1
            else:
                category_counts['其他事故'] += 1
    
    # 创建柱状图
    categories = list(category_counts.keys())
    counts = list(category_counts.values())
    
    plt.figure(figsize=(12, 8))
    
    # 设置中文字体
    plt.rcParams['font.sans-serif'] = ['SimHei', 'Microsoft YaHei', 'Arial Unicode MS', 'DejaVu Sans']
    plt.rcParams['axes.unicode_minus'] = False
    
    bars = plt.bar(categories, counts, color=['#FF6B6B', '#4ECDC4', '#45B7D1', '#96CEB4', '#FFEAA7'])
    
    # 添加数值标签
    for bar, count in zip(bars, counts):
        plt.text(bar.get_x() + bar.get_width()/2, bar.get_height() + 0.1, 
                str(count), ha='center', va='bottom', fontsize=12)
    
    plt.title('图4: 小米汽车事故类型分布', fontsize=16, pad=20)
    plt.xlabel('事故类型', fontsize=12)
    plt.ylabel('发生次数', fontsize=12)
    plt.xticks(rotation=45)
    plt.grid(axis='y', alpha=0.3)
    plt.tight_layout()
    plt.savefig('figures/xiaomi_car_accident_types.png', dpi=300, bbox_inches='tight')
    plt.close()
    
    log_info("事故类型分布图已保存至: figures/xiaomi_car_accident_types.png")

def generate_analysis_report(news_data, top_keywords, topics, output_path='reports/xiaomi_car_safety_analysis.md'):
    """生成分析报告"""
    log_info("生成分析报告...")
    
    # 确保输出目录存在
    os.makedirs('reports', exist_ok=True)
    
    # 统计事故相关新闻
    accident_news = [n for n in news_data if n['category'] == 'accident']
    safety_news = [n for n in news_data if n['category'] == 'safety']
    
    report_content = f"""# 小米汽车事故与安全分析报告

## 数据概览

- **分析时间**: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
- **新闻数量**: {len(news_data)} 条
- **事故相关新闻**: {len(accident_news)} 条
- **安全相关新闻**: {len(safety_news)} 条
- **时间范围**: 2024年3月 - 2024年11月

## 关键词分析

### 前20个高频关键词

| 排名 | 关键词 | 出现次数 |
|------|--------|----------|
"""

    # 添加关键词表格
    for i, (word, count) in enumerate(top_keywords[:20], 1):
        report_content += f"| {i} | {word} | {count} |\n"

    report_content += """
## 主题建模分析

通过LDA主题建模，识别出以下主要主题：

"""

    # 添加主题分析
    for topic in topics:
        report_content += f"### 主题 {topic['topic_id'] + 1}\n"
        report_content += f"**关键词**: {', '.join(topic['top_words'][:8])}\n\n"

    report_content += """
## 事故相关新闻详情

### 事故相关新闻列表

"""

    # 添加事故相关新闻详情
    accident_count = 0
    for news in news_data:
        if news['category'] == 'accident':
            accident_count += 1
            report_content += f"#### {accident_count}. {news['title']}\n"
            report_content += f"- **日期**: {news['date']}\n"
            report_content += f"- **来源**: {news['source']}\n"
            report_content += f"- **情感倾向**: {news['sentiment']}\n"
            report_content += f"- **内容**: {news['content']}\n\n"
    
    # 添加安全相关新闻统计
    report_content += f"## 安全相关新闻统计\n\n"
    report_content += f"- **安全认证新闻**: {len([n for n in news_data if n['category'] == 'safety'])} 条\n"
    report_content += f"- **召回相关新闻**: {len([n for n in news_data if n['category'] == 'recall'])} 条\n"
    report_content += f"- **测试相关新闻**: {len([n for n in news_data if n['category'] == 'testing'])} 条\n"
    report_content += f"- **自动驾驶新闻**: {len([n for n in news_data if n['category'] == 'autopilot'])} 条\n"

    report_content += """
## 可视化图表

### 图1: 关键词词云分析
![关键词词云图](../figures/xiaomi_car_wordcloud.png)

图1展示了小米汽车相关新闻中出现频率最高的关键词。采用爆炸形状设计，突出显示核心词汇，颜色渐变增强视觉效果。

### 图2: 实体关系网络图
![实体关系网络图](../figures/xiaomi_car_network.png)

图2显示了新闻中不同实体之间的关联关系，节点大小表示词汇出现频率，连线表示共现关系。

### 图3: 新闻情感分布
![新闻情感分布](../figures/xiaomi_car_sentiment_pie.png)

图3展示了新闻的情感倾向分布，包括正面、负面和中性新闻的比例。

### 图4: 事故类型分布
![事故类型分布](../figures/xiaomi_car_accident_types.png)

图4详细展示了不同类型的事故统计，帮助识别主要的安全问题类别。

## 分析总结

1. **事故类型分析**: 主要涉及刹车失灵、碰撞事故、自燃事故、雨天失控等
2. **安全措施**: 小米汽车已开展召回、安全测试、系统升级等安全措施
3. **时间分布**: 事故新闻在2024年4月-10月期间较为集中
4. **安全表现**: 同时存在安全认证通过、事故率低于平均等积极表现
5. **建议**: 建议小米汽车加强车辆稳定性测试，完善安全预警系统，提升事故应急响应能力

---
*本报告基于公开新闻数据生成，仅供参考*"""

    with open(output_path, 'w', encoding='utf-8') as f:
        f.write(report_content)
    
    log_info(f"分析报告已保存至: {output_path}")

def main():
    """主函数"""
    setup_environment()
    
    # 1. 收集数据
    news_data = search_xiaomi_car_news()
    
    # 2. 关键词分析
    top_keywords, word_freq = extract_keywords(news_data)
    
    # 3. 主题建模
    topics = perform_lda_analysis(news_data)
    
    # 4. 可视化
    create_wordcloud(word_freq)
    create_network_diagram(news_data)
    create_sentiment_pie_chart(news_data)
    create_accident_type_chart(news_data)
    
    # 5. 生成报告
    generate_analysis_report(news_data, top_keywords, topics)
    
    log_info("小米汽车事故与安全分析完成！")
    
    # 输出关键发现
    print("\n=== 关键发现 ===")
    print(f"总新闻数量: {len(news_data)}")
    print(f"事故相关新闻数量: {len([n for n in news_data if n['category'] == 'accident'])}")
    print(f"前5个高频关键词: {[word for word, count in top_keywords[:5]]}")
    print(f"识别出的主题数量: {len(topics)}")
    print("\n可视化图表已生成在 figures/ 目录")
    print("分析报告已生成在 reports/ 目录")

if __name__ == "__main__":
    main()
